#ifndef BELTCONTAINERSTRATEGY_H
#define BELTCONTAINERSTRATEGY_H

#pragma once

#include "../../ToolkitLayer.h"
#include "BoundedContainerStrategy.h"
#include <IBuffer/IBuffer.h>


/**
 * This strategy extends the BoundedContainerStrategy by adding an inner curve
 * defining a "hole" in the container. The inner curve and its border are also
 * splines with the same number of control points and subdivision levels as
 * their outer counterparts.
 *
 * This is based on the BoundedContainerGL class in the original implementation
 * of the Tabletop Framework done by T. Isenberg and A. Miede in the
 * Interactions Lab at the University of Calgary, Canada.
 *
 * @author Fabricio Anastacio - fabriciocfa@yahoo.com
 * @author Petra Isenberg - petra.isenberg@ucalgary.ca
 * @since August 23, 2007
 * @update August 6, 2008
 */
class TOOLKITLAYER_API BeltContainerStrategy : public BoundedContainerStrategy
{
	// Attributes
protected:
	/** The spline defining the outer bounds of the container. */
	Spline innerSpline;
	/** The spline defining the border of the outer bounds of the container. */
	Spline innerBorderSpline;
	/** The width of the belt (i.e., the width of the inner region. */
	float beltWidth;

	/** The display list identifier for the border. */
	unsigned int dlInnerBorder;
	/** The display list identifier for the border when selected. */
	unsigned int dlInnerBorderSelected;
	/** The display list identifier for the border when picking. */
	unsigned int dlInnerBorderPicking;

	// BUTTON BUFFER VALUES
	/** List of button values of each control point. */
	std::vector<unsigned char> cpInnerButtonValues;


	// Methods
public:
	/**
	 * Constructs a belt container strategy.
	 *
	 * @param bWidth the width of the inside region (belt) of the container.
	 * @param nControlPoints the number of control points.
	 * @param subdivLevels the number of times subdivision should be applied
	 * to the curve.
	 */
	BeltContainerStrategy(float bWidth = 100, unsigned int nControlPoints = 4, unsigned int subdivLevels = 4);
	/**
	 * Destroys this strategy.
	 */
	~BeltContainerStrategy(void);


	// ACCESSOR METHODS
	/**
	 * Returns the inner spline that defines this container bounds.
	 *
	 * @return the inner spline that defines this container bounds.
	 */
	inline Spline getInnerSpline() { return innerSpline; };
	/**
	 * Sets the inner spline that defines this container bounds.
	 *
	 * @param s the inner spline that defines this container bounds.
	 */
	inline void setInnerSpline(Spline s) { innerSpline = s; };
	/**
	 * Returns the inner border spline that defines this container bounds.
	 *
	 * @return the inner border spline that defines this container bounds.
	 */
	inline Spline getInnerBorderSpline() { return innerBorderSpline; };
	/**
	 * Sets the inner border spline that defines this container bounds.
	 *
	 * @param s the inner border spline that defines this container bounds.
	 */
	inline void setInnerBorderSpline(Spline s) { innerBorderSpline = s; };
	/**
	 * Returns the width of the belt (i.e., the inner region).
	 *
	 * @return the width of the belt (i.e., the inner region).
	 */
	inline float getBeltWidth() { return beltWidth; };
	/**
	 * Sets the width of the belt (i.e., the inner region).
	 *
	 * @param w the width of the belt (i.e., the inner region).
	 */
	inline void setBeltWidth(float w) { beltWidth = w; };

	/**
	 * Initializes the properties (i. e., i-buffers) of the associated
	 * component.
	 */
	void initProperties();

protected:
	/**
	 * Creates the display lists for drawing the container.
	 */
	virtual void createDisplayLists();
	/**
	 * Sets the control points of the bounding spline as an ellipse/rectangular
	 * shape.
	 *
	 * @param rounded if true the container has a rounded shape, otherwise its
	 * shape is rectangular.
	 */
	virtual void setDefaultBounds(bool rounded);
	/**
	 * Evaluates the splines for the outer bounds and its border using the
	 * current control points for the outer bounds spline.
	 */
	virtual void evaluateSplines();
	/**
	 * Calculates the inner border spline from the evaluated inner spline.
	 */
	void calculateInnerBorder();
	/**
	 * Adjusts the size of the associated component by obtaining the minimum
	 * and maximum coordinates of the region given by the bounded container
	 * splines (i.e., the axis-aligned bounding rectangle around the component)
	 * and the position of the associated component's center based on the
	 * calculated dimensions.
	 */
	virtual void adjustSizeAndPosition();

	/**
	 * Draws the inner region of the container.
	 */
	virtual void drawInnerRegion();
	/**
	 * Draws the border of the container.
	 *
	 * @param noColor if true the color of the vertices is not set.
	 */
	virtual void drawBorder(bool noColor = false);
	/**
	 * Draws the control points of the bounds spline of the container.
	 */
	virtual void drawControlPoints();

	/**
	 * Moves the control point given the specified index by the given values
	 * along the x- and y-axes.
	 *
	 * @param index the index of the control point.
	 * @param dx the displacement along the x-axis.
	 * @param dy the displacement along the y-axis.
	 */
	virtual void moveControlPointBy(unsigned int index, double dx, double dy);

	/**
	 * Fills the given buffer with the inside area, the border (movable), and
	 * the control points (incremental indices after last available).
	 *
	 * @param buffer the buffer to be filled.
	 */
	void fillButtonBuffer(IBuffer<unsigned char>* buffer);

	/**
	 * Initializes the list with the button values of the control points.
	 */
	virtual void initializeCPButtonValues();

	/**
	 * Handles the given event.
	 *
	 * @param evt the event to be handled.
	 */
	void onEvent(LargeDisplayEvent* evt);



};

#endif // BELTCONTAINERSTRATEGY_H
